在結束撰寫單元測試的技巧前,想再分享 ng-select 的測試方法。
開發過程中不難遇到會有 dropdown options 的元件,講者使用第三方 lib 的元件,叫做 ng-select。
樣式有這些,有興趣的讀者可以看看。
我們就來看看 spec 還可以怎麼寫
<ng-select
id="optionDropdown"
[items]="options"
[searchable]="false"
[clearable]="false"
[(ngModel)]="option"
(ngModelChange)="selectOption($event)"
></ng-select>
export class TestingNgSelectComponent {
title = 'example-angular-app';
options = [];
option = "";
public selectOption(val) {}
}
元件分別使用 query
, queryAll
這邊只拿 query
的方式做說明。
首先要先認識 line 36
,講者用 triggerKeyDownEvent 函式,來發動keydown事件。其中的 triggerEventHandler
是針對查詢到的元素,也就是 debugElement
發動事件。
那麼 spec 各別測試了什麼呢?
(1) 測試 selectOption
選擇項目的動作有沒有取到值,所以從範例來看,一開始會先建立 options 清單,接著偵測元素有沒有更新,然後 spy selectOption
,再取得 dropdown element。
準備好後,發動「按下空白鍵」,「往下選擇項目」,「按下 Enter」,最後預期 option 2 有被選取到。這樣的順序看起來有點抽象,讀者們可以到 這邊,實際跟著操作看看就大概知道了。
(2) 測試項目的值有沒有被更新,前面的配置一樣,最後預期元件的 option 會等於 option 2
describe('query', () => {
it('should call the function selectOption when the user selects a new value from the dropdown', () => {
//Assign
component.options = ['option 1','option 2','option 3'];
component.option = 'option 1';
componentFixture.detectChanges();
const spy = spyOn(component, 'selectOption');
const element = componentFixture.debugElement.query(By.css('#optionDropdown'));
//Act
triggerKeyDownEvent(element, 32); // space to open the dropdown
triggerKeyDownEvent(element, 40); // down arrow
triggerKeyDownEvent(element, 13); // enter to select second option and close the dropdown
//Assert
expect(spy).toHaveBeenCalledWith('option 2');
});
it('should update the field option when the user selects a new value from the dropdown', () => {
//Assign
component.options = ['option 1','option 2','option 3'];
component.option = 'option 1';
componentFixture.detectChanges();
const element = componentFixture.debugElement.query(By.css('#optionDropdown'));
//Act
triggerKeyDownEvent(element, 32); // space to open the dropdown
triggerKeyDownEvent(element, 40); // down arrow
triggerKeyDownEvent(element, 13); // enter to select second option and close the dropdown
//Assert
expect(component.option).toEqual('option 2');
});
})
function triggerKeyDownEvent(element: DebugElement, which: number, key = ''): void {
element.triggerEventHandler('keydown', {
which: which,
key: key,
preventDefault: () => { },
});
}
測試真的是很值得被開發的領域,雖然一開始並不被關注,但是深入瞭解後會發現小細節的地方,用UT就能先測到,不用等到整合測試才發現。